package com.cskaoyan.javase.oop2._1extends._11final._3variable._2member;

/**
 * final修饰成员变量表示该成员变量变成了一个常量,是一个成员常量
 * 它在内存中的位置，生命周期，使用方式等都不会改变。
 *
 * 语法：
 * [访问权限修饰符] final 数据类型 变量名;
 *
 * 如果直接在类中成员位置，写上述语法定义成员"常量"，肯定会报错。
 * 这是因为默认值不能当成final修饰成员变量的取值，
 * 常量意味着取值一旦确定就不能修改,也就是说最多赋值一次,而且也必须赋值一次
 * 所以这个赋值肯定不能依赖于默认值
 *
 * 必须 （在创建对象过程中）显式明确的给出一个值，而且这个值一旦给出就不可更改了。
 * 也就是说， 成员常量的赋值，有且必须有一次。
 * 目前我们给成员变量的赋值方式还有（除了默认初始化）：
 *      1.显式赋值
 *      2.构造器赋值
 *      3.构造代码块赋值
 *
 * 以上三种方式，选择其一即可，而且也必须，也只能选择其一。
 * 其它对象创建完毕后的赋值方式都不行。
 * 如果依赖构造器赋值，必须保证类的每个构造器都能完成final成员变量的赋值，否则会编译报错
 *
 * 最后思考： 成员"常量"是不是真正意义上的常量?
 *  不是，因为成员"常量"属于对象，每个对象可能都有自身的常量取值，完全可能不同，而真正意义上的常量，像PI这种
 *  是肯定不会因为创建对象而产生不同的。
 *  所以实际开发中，成员常量是很少见的。
 *  假如我们希望得到一个真正意义上的常量，在类的整个全局它的值都独一份，它应该是final修饰的静态成员变量。
 *
 * @since 10:51
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student(99999);
        System.out.println(s.age);
        System.out.println(s.id);
        System.out.println(s.name);
        // s.id = 88888;

        Student s2 = new Student(88888);
        System.out.println(s2.id);
    }
}

class Student {
    // Variable 'age' might not have been initialized
    final int age = 19;
    final String name;
    final int id;
    {
        // Cannot assign a value to final variable 'age'
        // age = 20;
        name = "张三";
    }

    public Student(int id) {
        this.id = id;
    }

    /*
        一个构造器就是一种new对象的方式
        如果外界使用无参创建对象
        就会final int id没有赋值,常量没有赋值,显然是不行的
     */
    // public Student() {
    //     id = 100;
    // }
}